﻿#pragma once

#include <qobject.h>
#include <qrunnable.h>
#include <qthreadpool.h>
#include <qfile.h>
#include <qhash.h>
#include <qmutex.h>
#include <qlist.h>

class FileWriter1 :public QObject,public QRunnable
{
  Q_OBJECT
private:
  QString filePath = "";
  QByteArray data;
  QFile::OpenModeFlag openModeFlag= QFile::WriteOnly;
  friend class FileWriter;

private:
  FileWriter1(QString filePath, QByteArray data, QFile::OpenModeFlag openModeFlag);
  ~FileWriter1();
signals:
  void signal_writeFileSuccessful(QString filePath);
  void signal_writeFileFailed(QString filePath);
  void signal_runningFinished(QString filePath);
public:
  void run();
};

class FileWriter : public QObject
{
  Q_OBJECT
public:
  enum SaveFileMode
  {
    WriteToFile,
    AppendToFile
  };
private:
  QMutex locker;
  QHash<QString, QList<FileWriter1*>> missionQueue;
  QThreadPool* qThreadPool=Q_NULLPTR;
public:
  FileWriter(QObject* parent = Q_NULLPTR);
  ~FileWriter();

public:
  template<class FileDataRecorder>
  void saveAsFile(QString filePath, QByteArray data, SaveFileMode saveFileMode, FileDataRecorder* fileDataRecorder = Q_NULLPTR,void(FileDataRecorder::* wirteFileSuccessful)(QString)=Q_NULLPTR, void(FileDataRecorder::* wirteFileFailed)(QString) = Q_NULLPTR)
  {
    FileWriter1* fileWriter1 = new FileWriter1(filePath, data, getOpenMode(saveFileMode));
    fileWriter1->setAutoDelete(true);
    connect(fileWriter1, &FileWriter1::signal_runningFinished, this, &FileWriter::slot_continueRun, Qt::QueuedConnection);
    if (Q_NULLPTR!= fileDataRecorder)
      {
        if (Q_NULLPTR!= wirteFileSuccessful)
          {
            connect(fileWriter1, &FileWriter1::signal_writeFileSuccessful, fileDataRecorder, wirteFileSuccessful, Qt::QueuedConnection);
          }
        if (Q_NULLPTR != wirteFileFailed)
          {
            connect(fileWriter1, &FileWriter1::signal_writeFileFailed, fileDataRecorder, wirteFileFailed, Qt::QueuedConnection);
          }
      }
    locker.lock();
    if (missionQueue.contains(filePath))
      {
        QList<FileWriter1*> temp = missionQueue.take(filePath);
        temp.append(fileWriter1);
        missionQueue.insert(filePath, temp);
      }
    else
      {
        QList<FileWriter1*> temp;
        temp.append(fileWriter1);
        missionQueue.insert(filePath, temp);
        qThreadPool->start(fileWriter1);
      }
    locker.unlock();
  }
private slots:
  void slot_continueRun(QString filePath);
private:
  static QFile::OpenModeFlag getOpenMode(SaveFileMode saveFileMode)
  {
    switch (saveFileMode)
      {
      case FileWriter::WriteToFile:
        return QFile::WriteOnly;
      case FileWriter::AppendToFile:
        return QFile::Append;
      default:
        return QFile::Append;
      }
  }
public:
  QThreadPool* getQThreadPool();
  void setQThreadPool(QThreadPool* qThreadPool);
};
